package com.embracesource.gracefulresponse.advice;

import com.embracesource.gracefulresponse.api.ResponseFactory;
import com.embracesource.gracefulresponse.api.ResponseStatusFactory;
import com.embracesource.gracefulresponse.data.Response;
import com.embracesource.gracefulresponse.data.ResponseStatus;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

/**
 * 非空返回值的处理.
 *
 * @author <a href="mailto:943868899@qq.com">Yujie</a>
 * @version 0.1
 * @since 0.1
 */
@Order(value = 1000)
@ControllerAdvice
public class NotVoidResponseBodyAdvice implements ResponseBodyAdvice<Object> {
    
    @Resource
    private ResponseFactory responseFactory;

    @Resource
    private ResponseStatusFactory responseStatusFactory;

    /**
     * 只处理不返回void的，并且MappingJackson2HttpMessageConverter支持的类型.
     *
     * @param methodParameter 方法参数
     * @param clazz           处理器
     * @return 是否支持
     */
    @Override
    public boolean supports(MethodParameter methodParameter,
                            Class<? extends HttpMessageConverter<?>> clazz) {

        return !Objects.requireNonNull(methodParameter.getMethod()).getReturnType().equals(Void.TYPE)
                && MappingJackson2HttpMessageConverter.class.isAssignableFrom(clazz);
    }

    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> clazz,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        if (body == null) {
            serverHttpResponse.setStatusCode(HttpStatus.OK);
            return responseFactory.newSuccessInstance().getPayload();
        } else if (body instanceof Map) {
            Map map = (Map) body;
            int status = (Integer)map.get("status");
            String path = (String) map.get("path");
            String error = (String) map.get("error");
            serverHttpResponse.setStatusCode(HttpStatus.valueOf(status));
            ResponseStatus responseStatus = responseStatusFactory.defaultError(HttpStatus.valueOf(status));
            return responseStatus;
        } else if (body instanceof Response) {
            Response response = (Response) body;
            ResponseStatus status = response.getStatus();
            if(status != null) {
                if(status.getHttpStatus() != null) {
                    //有异常时，设置响应状态码
                    serverHttpResponse.setStatusCode(response.getStatus().getHttpStatus());
                }
            }
            return response.getPayload();
        } else {
            serverHttpResponse.setStatusCode(HttpStatus.OK);
            return responseFactory.newSuccessInstance(body).getPayload();
        }
    }
}
